package com.un.ebs.sys.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.un.ebs.core.enums.SexEnum;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.core.util.WebResult;
import com.un.ebs.core.util.WebUtils;
import com.un.ebs.customer.service.CustomerService;
import com.un.ebs.customer.service.DefunctService;
import com.un.ebs.sys.domain.AppTenant;
import com.un.ebs.sys.domain.DictionaryValueExt;
import com.un.ebs.sys.domain.Ent;
import com.un.ebs.sys.dto.UserRegisterByWxDto;
import com.un.ebs.sys.dto.WxUserInfoDto;
import com.un.ebs.sys.mapper.DictionaryValueExtMapper;
import com.un.ebs.sys.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.Date;

/**
 * @author Administrator
 */
@RestController
@RequestMapping("/wx")
@Api(value = "sys-wx", description = "微信接口")
public class WxController {

    @Autowired
    private WxService wxService;

    @Autowired
    private EntService entService;

    @Autowired
    private UserService userService;

    @Autowired
    private AppTenantService appTenantService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private DictionaryValueExtMapper dictionaryValueExtMapper;

//    @Autowired
//    private RedisUtil redisUtil;

    @Autowired
    private RedisService redisService;

    @Autowired
    private DefunctService defunctService;

    @GetMapping(value = "/checkSignature", produces = {"text/plain;charset=UTF-8"})
    @ApiOperation(value = "checkSignature")
    public String callBack(@RequestParam(name = "signature", required = false) String signature,
                           @RequestParam(name = "timestamp", required = false) String timestamp,
                           @RequestParam(name = "nonce", required = false) String nonce,
                           @RequestParam(name = "echostr", required = false) String echostr) {
        System.out.println(new Date() + " : checkSignature. " + signature + "," + timestamp + "," + nonce + "," + echostr);

        if (wxService.getWxMpService().checkSignature(timestamp, nonce, signature)) {
            return echostr;
        } else {
            return null;
        }
    }

    @PostMapping(value = "/jsapiSignature")
    @ApiOperation(value = "URL签名")
    public WebResult<WxJsapiSignature> wxJsSdkConfig(@RequestParam String tenantId, @RequestParam String url) {
        try {
            return WebUtils.success(wxService.getWxMpService(tenantId).createJsapiSignature(URLDecoder.decode(url, "UTF-8")));
        } catch (IOException e) {
            return WebUtils.error(e);
        } catch (WxErrorException e) {
            return WebUtils.error(e);
        }
    }

    @GetMapping(value = "/getWxJsapiTicket")
    @ApiOperation(value = "获取jsapiTicket")
    public WebResult getWxJsapiTicket(@RequestParam String tenantId) {
        try {
            return WebUtils.success(wxService.getWxMpService(tenantId).getJsapiTicket());
        } catch (WxErrorException e) {
            LoggerFactory.getLogger(this.getClass()).error(e.getError().getErrorCode() + ":" + e.getError().getErrorMsg());
            e.printStackTrace();
            return WebUtils.error(e);
        }
    }

    @PostMapping(value = "createUser")
    @ApiOperation(value = "微信用户作为客户注册。")
    public WebResult<WxUserInfoDto> createUser(@RequestParam(required = true) @ApiParam("loginByCode后返回数据中的openId") String openId,
                                               @RequestParam(required = false) @ApiParam("当前用户姓名，如果没有给，则系统取微信呢称") String name,
                                               @RequestParam @ApiParam("用户手机号码") String phone,
                                               @RequestParam @ApiParam("用户手机验证码，通过user/SendRegisterCode获得") String smsCode,
                                               @RequestParam @ApiParam("当前的租户ID，替代原来的entId参数") String tenantId) {

        if (!("99999999").equals(smsCode)) {
            if (!userService.checkRegisterCode(phone, smsCode)) {
                throw new BusinessException("手机验证码不正确。");
            }
        }

        AppTenant tenant = appTenantService.queryById(tenantId);
        if (tenant == null) {
            throw new BusinessException("指定的租户ID无效。");
        }

        UserRegisterByWxDto wxuser = new UserRegisterByWxDto();
        wxuser.setOpenId(openId);
        wxuser.setName(name);
        wxuser.setPhone(phone);
        wxuser.setTenantId(tenantId);
        userService.addByWx(wxuser);

        return getBindInfo(openId, tenant.getEntId(), tenantId);

    }

    @PostMapping(value = "loginByMa/{tenantId}")
    @ApiOperation(value = "微信小程序登录")
    public WebResult<WxUserInfoDto> loginByMa(@PathVariable("tenantId") String tenantId, @RequestBody WxMaUserInfo user) {
        userService.addByWx(user.getNickName(), user.getOpenId(), user.getAvatarUrl(), tenantId);
        redisService.set(user.getOpenId(), convert(user), 60 * 60L);
        return WebUtils.success(getBindInfo(user.getOpenId(), null, tenantId));
    }

    @PostMapping(value = "loginByMinAppOpenId")
    @ApiOperation(value = "微信小程序登录，获取Ebs Token")
    public WebResult loginByMinAppOpenId(String openId, String tenantId) {
        return WebUtils.success(userService.getOpenId(openId, tenantId));
    }

    @PostMapping(value = "loginByMiniApp/{tenantId}")
    @ApiOperation(value = "微信小程序登录")
    public WebResult loginByMiniApp(@PathVariable("tenantId") String tenantId, @RequestParam @ApiParam("wx.login后得到") String jsCode,
                                    @RequestParam(required = false) @ApiParam("wx.getUserInfo后得到") String encryptedData,
                                    @RequestParam(required = false) @ApiParam("wx.getUserInfo后得到") String ivStr) throws WxErrorException {

        WxMaService wx = wxService.getWxMaService(tenantId);
        WxMaJscode2SessionResult ret = wx.getUserService().getSessionInfo(jsCode);

        if (!StringUtils.isNullOrEmpty(encryptedData) && !StringUtils.isNullOrEmpty(ivStr)) {
            WxMaUserInfo user = wx.getUserService().getUserInfo(ret.getSessionKey(), encryptedData, ivStr);
            //redisService.set(user.getOpenId(), convert(user), 60 * 60L);
            return WebUtils.success(user);
        } else {
            //redisService.set(ret.getOpenid(), convert(ret), 60 * 60L);
            return WebUtils.success(ret);
        }
        //redisService.set(ret.getOpenid(), convert(ret), 60 * 60L);
        //return WebUtils.success(ret);
    }

    @PostMapping(value = "sendSubscribeMsg")
    @ApiOperation(value = "发送订阅消息")
    public WebResult sendSubscribeMsg(@RequestParam String openId, @RequestParam String templateId, @RequestParam String tenantId) throws WxErrorException {
        WxMaSubscribeMessage msg = new WxMaSubscribeMessage();
        msg.addData(new WxMaSubscribeMessage.MsgData("thing1", "基本户"));
        msg.addData(new WxMaSubscribeMessage.MsgData("thing2", "刘博"));
        msg.addData(new WxMaSubscribeMessage.MsgData("amount3", "88500.00"));
        msg.addData(new WxMaSubscribeMessage.MsgData("thing4", DateUtils.formatDate(new Date(), "yyyy-MM-dd")));
        msg.setTemplateId(templateId);
        msg.setToUser(openId);

        wxService.getWxMaService(tenantId).getMsgService().sendSubscribeMsg(msg);
        return WebUtils.success();
    }

    private WxMpUser convert(WxMaUserInfo user) {
        WxMpUser ret = new WxMpUser();
        ret.setNickname(user.getNickName());
        ret.setOpenId(user.getOpenId());
        ret.setHeadImgUrl(user.getAvatarUrl());
        ret.setUnionId(user.getUnionId());
        ret.setLanguage(user.getLanguage());
        return ret;
    }

    private WxMpUser convert(WxMaJscode2SessionResult user) {
        WxMpUser ret = new WxMpUser();
        ret.setOpenId(user.getOpenid());
        ret.setUnionId(user.getUnionid());
        return ret;
    }

    @GetMapping(value = "loginByWx")
    @ApiOperation(value = "微信用户手机实名注册，注册后才能进行业务操作，操作执行后，返回用户信息")
    public WebResult<WxUserInfoDto> loginByWx(@RequestParam @ApiParam("微信的认证code，通过微信接口获得") String code,
                                              @RequestParam @ApiParam("EBS系统中的租户ID，通过EBS系统获得") String tenantId, @RequestParam(required = false) @ApiParam("是否自动绑定") Boolean isAutoBind) {
        WxMpUser wxMpUser = wxService.getUserInfo(null, tenantId, code);

        if (isAutoBind == null) {
            isAutoBind = false;
        }

        if (isAutoBind) {
            userService.addByWx(StringUtils.isNullOrEmpty(wxMpUser.getNickname()) ? "微信用户" : wxMpUser.getNickname(), wxMpUser.getOpenId(), wxMpUser.getHeadImgUrl(), tenantId);
        }
        return getBindInfo(wxMpUser.getOpenId(), null, tenantId);
    }

    @PostMapping(value = "cancelWxBind")
    @ApiOperation(value = "解除微信OpenID与租户的绑定关系。")
    public WebResult cancelWxBind(@RequestParam String openId, @RequestParam String tenantId) {
        userService.cancelWxBind(openId, tenantId);
        return WebUtils.success();
    }

    @PostMapping(value = "login/{tenantId}/{openId}")
    @ApiOperation(value = "微信用户手机实名注册，注册后才能进行业务操作，操作执行后，返回用户信息")
    public WebResult login(@PathVariable("tenantId") String tenantId, @PathVariable("openId") String openId, @RequestParam(required = false) @ApiParam("是否自动绑定") Boolean isAutoBind, @RequestBody(required = false) WxMaUserInfo user) {
        AppTenant tenant = appTenantService.queryById(tenantId);
        if (tenant == null) {
            throw new BusinessException("指定的租户ID无效。");
        }
        if (isAutoBind) {
            userService.addByWx(user.getNickName(), user.getOpenId(), user.getAvatarUrl(), tenantId);
            redisService.set(user.getOpenId(), convert(user), 60 * 60L);
            return WebUtils.success(getBindInfo(user.getOpenId(), null, tenantId));
        }
        return WebUtils.success(getBindInfo(openId, tenant.getEntId(), tenantId));
    }

    @GetMapping("loginByCode")
    @ApiOperation(value = "请更换为loginByWx接口", notes = "")
    public WebResult<WxUserInfoDto> loginByCode(@RequestParam String code, @RequestParam String entId) {
        return getBindInfo(wxService.getOpenId(entId, null, code), entId, null);
    }

    @Deprecated
    private WebResult getBindInfo(String openId) {
        return getBindInfo(openId, null, null);
    }

    private WebResult getBindInfo(String openId, String entId, String tenantId) {
        WxUserInfoDto result = new WxUserInfoDto();
        try {
            result.setWxUser(redisService.get(openId));
        } catch (Exception e) {
            e.printStackTrace();
            result.setIsBindStatus(false);
            return WebUtils.error(-100, e.getMessage(), result);
        }

        try {
            if (userService.bindStatus(openId, tenantId)) {
                result.setIsBindStatus(true);
                result.setToken(userService.loginByOpenId(openId, tenantId, result.getWxUser()));
                result.setEbsUser(userService.getUserExt(null, openId));
                result.setEbsUserAddress(customerService.queryAddrByUserId(result.getEbsUser().getId()));
            } else {
                result.setIsBindStatus(false);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return WebUtils.error(e);
        }
        return WebUtils.success(result);
    }

    @PostMapping("bindToUser")
    @ApiOperation(value = "当前OpenId绑定到EBS用户账号")
    public WebResult bindToUser(
            @RequestParam(required = false) String entId,
            @RequestParam String openId,
            @RequestParam String phone,
            @RequestParam String verificationCode,
            @RequestParam(required = false) String tenantId) {
        if (!userService.checkRegisterCode(phone, verificationCode)) {
            throw new BusinessException("验证码不正确。");
        }
        userService.bindUserToPersonnel(openId, phone, tenantId);
        return getBindInfo(openId, entId, tenantId);
    }

    @PostMapping("bindToCustomer")
    @ApiOperation(value = "当前OpenId绑定到已有EBS客户")
    public WebResult bindToCustomer(
            @RequestParam String entId,
            @RequestParam String openId,
            @RequestParam String custId,
            @RequestParam String phone,
            @RequestParam String verificationCode) {
        userService.checkRegisterCode(phone, verificationCode);
        customerService.bindToUser(custId, openId);
        return getBindInfo(openId, entId, null);
    }

    @PostMapping("bindUserToPersonnel")
    @ApiOperation(value = "临时接口")
    public WebResult bindUserToPersonnel(@RequestParam String openId, @RequestParam String phone, @RequestParam String tenantId) {
        userService.bindUserToPersonnel(openId, phone, tenantId);
        return WebUtils.success();
    }

    @PostMapping("bindToDefunct")
    @ApiOperation(value = "绑定到逝者")
    public WebResult bindToDefunct(@RequestParam String entId, @RequestParam String defunctId, @RequestParam String openId, @RequestParam String phone, @RequestParam String verificationCode) {
        try {
            WxMpUser wxMpUser = wxService.getWxMpService(null, entId).getUserService().userInfo(openId);
            SexEnum sexEnum;
            switch (wxMpUser.getSex()) {
                case 1:
                    sexEnum = SexEnum.Male;
                    break;
                case 2:
                    sexEnum = SexEnum.Female;
                    break;
                default:
                    sexEnum = SexEnum.Notdefine;
                    break;
            }
            defunctService.newCustBind(entId, wxMpUser.getNickname(), sexEnum, phone, openId, defunctId);
            return getBindInfo(openId, entId, null);
        } catch (WxErrorException e) {
            return WebUtils.error(e);
        }
    }

    @PostMapping("bind")
    @ApiOperation(value = "当前OpenId绑定到客户或者员工")
    public WebResult bind(@RequestParam String entId, @RequestParam String openId, @RequestParam String phone, @RequestParam String verificationCode) {
        if (!userService.checkRegisterCode(phone, verificationCode)) {
            throw new BusinessException("验证码无效。");
        }
        if (!customerService.bindToUser(entId, phone, openId)) {
            //客户未绑定上，再以工作人员绑定
            userService.bindOpenId(openId, phone, verificationCode);
        }
        return getBindInfo(openId, entId, null);
    }

    /**
     * 绑定到已有客户
     *
     * @param openId
     * @param verificationCode
     * @return
     */
    @PostMapping("bindToCust")
    @ApiOperation(value = "当前OpenId绑定到已有客户")
    public WebResult bindToCust(@RequestParam String openId, @RequestParam String verificationCode) {
        // TODO: 2020/2/28 当前openId绑定到已有客户，根据手机号码。此逻辑需要重新验证，原来用于明阳山业务的
        String custId = "stringRedisTemplate.opsForValue().get(verificationCode)";
        if (StringUtils.isNullOrEmpty(custId)) {
            throw new BusinessException("验证码无效。");
        }
        customerService.bindToUser(custId, openId);
        return getBindInfo(openId);
    }

    @GetMapping("getAppId")
    @ApiOperation(value = "根据企业ID获取微信公众号的AppId")
    public WebResult getAppId(@RequestParam String entId) {
        Ent ent = entService.queryById(entId);
        if (ent == null) {
            return WebUtils.success();
        }
        return WebUtils.success(ent.getWxAppId());
    }

    @GetMapping("getWxAppId")
    @ApiOperation(value = "根据租户ID获取微信公众号的AppId")
    public WebResult getWxAppId(@RequestParam String tenantId) {
        AppTenant tenant = appTenantService.queryById(tenantId);
        if (tenant == null) {
            throw new BusinessException("指定的租户没有找到。");
        }
        Ent ent = entService.queryByTenantId(tenantId);
        if (ent == null) {
            return WebUtils.success();
        }
        return WebUtils.success(ent.getWxAppId());
    }

    @GetMapping("getQrcodeByScene")
    @ApiOperation(value = "生成渠道二维码，永久有效")
    public WebResult getQrcodeByScene(@RequestParam String scene) {
        DictionaryValueExt value = dictionaryValueExtMapper.selectById(scene);
        if (value == null) {
            throw new BusinessException("场景值没有找到。");
        }
        if (!value.getCode().equals("wx_scene")) {
            throw new BusinessException("指定的场景值不是一个有效的 wx_scene 字典值。");
        }
        WxMpQrCodeTicket ticket = null;
        try {
            ticket = wxService.getWxMpService().getQrcodeService().qrCodeCreateLastTicket(scene);
            return WebUtils.success(ticket);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return WebUtils.error(e);
        }
    }

    @GetMapping("getQrcodeByTemp")
    @ApiOperation(value = "生成渠道二维码，需要指定有效时间")
    public WebResult getQrcodeByTemp(@RequestParam String scene, @RequestParam Integer expireSeconds) {
        WxMpQrCodeTicket ticket = null;
        try {
            ticket = wxService.getWxMpService().getQrcodeService().qrCodeCreateTmpTicket(scene, expireSeconds);
            return WebUtils.success(ticket);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return WebUtils.error(e);
        }
    }
}
